package com.rykj.energy.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.rykj.energy.common.enums.HTTPMETHOD;
import com.rykj.energy.common.enums.HttpErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

//import org.apache.http.protocol.HTTP;

/**
 * 所属类别:http请求工具类<br/>
 * Author:<a href="mailto:lilong@tsinghuabigdata.com">lilong</a> <br/>
 * Date:2015-1-14 上午10:42:27<br/>
 * Version:1.0 <br/>
 */
@Slf4j
public class HttpClientUtils {
    final static int TIMEOUT = 15 * 1000;
    final static String CHARSET = "UTF-8";
    final static int OK = 200;
    final static int DIR = 300;

    /**
     * 方法描述:发送POST请求<br/>
     * Author:<a href="mailto:lilong@tsinghuabigdata.com">lilong</a> <br/>
     * Date:2015-1-14 上午10:42:40<br/>
     * Version:1.0 <br/>
     *
     * @param url          请求URL（全路径）
     * @param params(请求参数)
     * @return 返回结果
     */
    public static String post(String url, Map<String, String> params) throws Exception {
        URL urlObject = new URL(url);
        HttpURLConnection connection = (HttpURLConnection) urlObject.openConnection();
        connection.setConnectTimeout(TIMEOUT);
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
        connection.setRequestProperty("Accept", "application/json");
        connection.setRequestProperty("Accept-Charset", CHARSET);

        connection.connect();
        OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), CHARSET);
        writer.write(requestData(params));
        writer.flush();
        writer.close();

        InputStream stream = (connection.getResponseCode() != 200) ? connection.getErrorStream() : connection.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(stream, CHARSET));
        StringBuffer result = new StringBuffer();

        String output;
        while ((output = reader.readLine()) != null) {
            result.append(output);
        }
        writer.close();
        stream.close();
        reader.close();
        connection.disconnect();
        return result.toString();
    }

    public static String get(String url) throws IOException {
        System.setProperty("jsse.enableSNIExtension", "false");
        URL urlObject = new URL(url);
        HttpURLConnection connection = (HttpURLConnection) urlObject.openConnection();
        connection.setConnectTimeout(TIMEOUT);
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setRequestMethod("GET");
//		connection.setRequestProperty("Cookie", "wxsid=xdfL80D/bNsv8ehz;wxuin=1219688940");
        connection.connect();
        InputStream stream = (connection.getResponseCode() != 200) ? connection.getErrorStream() : connection.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(stream, CHARSET));
        StringBuffer result = new StringBuffer();

        String output;
        while ((output = reader.readLine()) != null) {
            result.append(output);
        }
        stream.close();
        reader.close();
        connection.disconnect();
        return result.toString();
    }

    /**
     * 方法描述:构建请求参数 <br/>
     * Author:<a href="mailto:lilong@tsinghuabigdata.com">lilong</a> <br/>
     * Date:2015-1-14 上午10:40:44<br/>
     * Version:1.0 <br/>
     *
     * @param params
     * @return
     */
    private static String requestData(Map<String, String> params) {
        // 构建请求参数
        if (params == null) {
            return null;
        }
        StringBuffer buffer = new StringBuffer();
        for (Entry<String, String> entry : params.entrySet()) {
            buffer.append(entry.getKey());
            buffer.append("=");
            buffer.append(entry.getValue());
            buffer.append("&");
        }
        int bufferLen = buffer.length();
        if (bufferLen > 1) {
            buffer.substring(0, bufferLen - 1);
        }
        return buffer.toString();
    }

    /**
     * put方式请求
     *
     * @param url  接口地址
     * @param json 请求参数(json格式)
     * @return
     * @throws Exception
     */
    public static String put(String url, String json) throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPut put = new HttpPut(url);
        put.setHeader("Content-Type", "application/json;charset=UTF-8");
        put.setEntity(new StringEntity(json));

        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(100).setConnectionRequestTimeout(100)
                .setSocketTimeout(100).build();
        put.setConfig(requestConfig);

        //Create a custom response handler
        ResponseHandler<String> responseHandler = getResponse();
        String responseBody = httpClient.execute(put, responseHandler);
        log.info(responseBody);
        return responseBody;
    }

    /**
     * post方式请求
     *
     * @param url  接口地址
     * @param json 请求参数(json格式)
     * @return
     * @throws Exception
     */
    public static String post(String url, String json) throws Exception {
        try {
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpPost post = new HttpPost(url);
            post.setHeader("Content-Type", "application/json;charset=UTF-8");
            post.setEntity(new StringEntity(json, "utf-8"));

            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(20000).setConnectionRequestTimeout(20000)
                    .setSocketTimeout(20000).build();
            post.setConfig(requestConfig);

            //Create a custom response handler
            ResponseHandler<String> responseHandler = getResponse();
            String responseBody = httpClient.execute(post, responseHandler);
            return  responseBody;
        }catch (ConnectTimeoutException e){
            log.error(url);
            log.error("", e);
            throw new ConnectTimeoutException(HttpErrorCode.TIME_OUT.getMessage());
//            result.setContent(HttpErrorCode.TIME_OUT.getMessage());
//            result.setCode(HttpErrorCode.TIME_OUT.getCode());
        }catch (HttpHostConnectException e){
            log.error(url);
            log.error("", e);
            throw new Exception(HttpErrorCode.CONNECTION_REFUSED.getMessage());
        }catch (ClientProtocolException e){
            log.error(url);
            log.error("", e);
            throw new ClientProtocolException(HttpErrorCode.UNKNOW_RESPONSE.getMessage());
        } catch (IOException e) {
            log.error(url);
            log.error("", e);
            throw new IOException(HttpErrorCode.IO_ERROR.getMessage());
        }
    }

    /**
     * post方式请求   加上token
     *
     * @param url  接口地址
     * @param json 请求参数(json格式)
     * @return
     * @throws Exception
     */
    public static String postWithToken(String url, String json,String token) throws Exception {
        try {
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpPost post = new HttpPost(url);
            post.setHeader("Content-Type", "application/json;charset=UTF-8");
            post.setHeader("token",token);
            post.setEntity(new StringEntity(json, "utf-8"));

            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(20000).setConnectionRequestTimeout(20000)
                    .setSocketTimeout(20000).build();
            post.setConfig(requestConfig);

            //Create a custom response handler
            ResponseHandler<String> responseHandler = getResponse();
            String responseBody = httpClient.execute(post, responseHandler);
            return  responseBody;
        }catch (ConnectTimeoutException e){
            log.error(url);
            log.error("", e);
            throw  new ConnectTimeoutException(HttpErrorCode.TIME_OUT.getMessage());
        }catch (HttpHostConnectException e){
            log.error(url);
            log.error("", e);
            throw  new Exception(HttpErrorCode.CONNECTION_REFUSED.getMessage());
        }catch (ClientProtocolException e){
            log.error(url);
            log.error("", e);
            throw  new ClientProtocolException(HttpErrorCode.UNKNOW_RESPONSE.getMessage());
        } catch (IOException e) {
            log.error(url);
            log.error("", e);
            throw  new IOException(HttpErrorCode.IO_ERROR.getMessage());
        }
    }

    /**
     * post方式请求
     *
     * @param url  接口地址
     * @param json 请求参数(json格式)
     * @return
     * @throws Exception
     */
    public static String postStr(String url, String json){
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost post = new HttpPost(url);
        post.setHeader("Content-Type", "application/json;charset=UTF-8");
        post.setEntity(new StringEntity(json,"utf-8"));

        //Create a custom response handler
        ResponseHandler<String> responseHandler = getResponse();
        String responseBody = null;
        try {
            responseBody = httpClient.execute(post, responseHandler);
        } catch (Exception e) {
            log.error("请求失败,URL[{}], 参数[{}]", url, json);
            e.printStackTrace();
        }
        log.info(responseBody);
        return responseBody;
    }


    /**
     * delete方式请求
     *
     * @param url  接口地址
     * @param json 请求参数(json格式)
     * @return
     * @throws Exception
     */
    public static String delete(String url, String json) throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpDelete delete = new HttpDelete(url);
        delete.setHeader("Content-Type", "application/json;charset=UTF-8");

        //Create a custom response handler
        ResponseHandler<String> responseHandler = getResponse();
        String responseBody = httpClient.execute(delete, responseHandler);
        log.info(responseBody);
        return responseBody;
    }

    private static ResponseHandler<String> getResponse() {
        ResponseHandler<String> responseHandler = response -> {
            int status = response.getStatusLine().getStatusCode();
            response.setHeader("Content-Type", "application/json;charset=UTF-8");
            if (status >= OK && status < DIR) {
                HttpEntity entity = response.getEntity();
                return entity != null ? EntityUtils.toString(entity) : null;
            } else {
                throw new ClientProtocolException("Unexpection response status: " + status);
            }
        };
        return responseHandler;
    }


    /**
     *
     * @param imageUrls
     * @return fileNameList 文件名列表
     */
    public static List<String> downloadCameraImages(List<String> imageUrls, String filePath) {
        List<String> result = Lists.newArrayList();
        imageUrls.forEach(url->{
            try {
                String[] urlArr = url.split("/");
                String fileName = urlArr[urlArr.length - 1];
                String filefullPath = filePath + FileUtils.CAMERA_IMG_PATH + fileName;
                downloadFile(url, filefullPath);
                result.add(fileName);
            }catch (Exception e){
                log.error(url+"下载失败",e);
            }
        });
        return result;
    }


    public static void downloadFile(String fileUrl, String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }

        OutputStream os = new FileOutputStream(file);
        URL url = new URL(fileUrl);
        InputStream is = url.openStream();
        byte[] buff = new byte[1024];
        while (true) {
            int readed = is.read(buff);
            if (readed == -1) {
                break;
            }
            byte[] temp = new byte[readed];
            System.arraycopy(buff, 0, temp, 0, readed);
            os.write(temp);
        }
        is.close();
        os.close();
    }

    /**
     * form data 提交方式
     *
     * @param url
     * @param param
     * @return
     */
    public static String doPost(String url, Map<String, String> param) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建参数列表
            if (param != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList, "utf-8");
                httpPost.setEntity(entity);
            }
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                log.debug("错误异常 {}", e);
            }
        }
        return resultString;
    }


    /**
     * 上传图片(二进制的方式)
     *
     * @param url
     * @param filePath
     * @throws Exception
     */
    public static String upload(String url, String filePath) throws IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(6000).build();
        httpPost.setConfig(requestConfig);
        byte[] bytes = FileUtils.getImageBinary(filePath);
        httpPost.setEntity(new ByteArrayEntity(bytes));
        httpPost.setHeader("Content-type", "binary/octet-stream");
        CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
        String resultString = EntityUtils.toString(httpResponse.getEntity(), "utf-8");
        return resultString;
    }

    /**
     * 上传文件
     *
     * @param url     接口
     * @param builder 参数
     * @return
     * @throws IOException
     */
    public static String upload(String url, MultipartEntityBuilder builder) throws IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        String result = "";
        HttpPost httpPost = new HttpPost(url);
//        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
//        builder.addBinaryBody("file", file.getInputStream(), ContentType.MULTIPART_FORM_DATA, fileName);// 文件流
//        builder.addTextBody("filename", fileName);// 类似浏览器表单提交，对应input的name和value
        HttpEntity entity = builder.build();
        httpPost.setEntity(entity);
        // 执行提交
        HttpResponse response = httpClient.execute(httpPost);
        HttpEntity responseEntity = response.getEntity();
        if (responseEntity != null) {
            // 将响应内容转换为字符串
            result = EntityUtils.toString(responseEntity, Charset.forName("UTF-8"));
        }
//        log.info("上传文件将响应内容result===" + result);
        return result;
    }

    public static <T> T postMsg(String url, Map<String, String> header, Object content, Class<T> resultType) {
        return sendMsg(url, HTTPMETHOD.POST, header, content, null, resultType);
    }

    public static <T> T postMsg(String url,Map<String, String> header, Map<String, String> params, Class<T> resultType) {
        return sendMsg(url, HTTPMETHOD.POST, header, null, params, resultType);
    }

    public static <T> T getMsg(String url, Map<String, String> header, Map<String, String> params, Class<T> resultType) {
        return sendMsg(url, HTTPMETHOD.GET, header, null, params, resultType);
    }

    public static <T> T postMsg(String url,Object content, Class<T> resultType) {
        return sendMsg(url, HTTPMETHOD.POST, null, content, null, resultType);
    }

    public static <T> T postMsg(String url, Map<String, String> params, Class<T> resultType) {
        return sendMsg(url, HTTPMETHOD.POST, null, null, params, resultType);
    }

    public static <T> T getMsg(String url,Map<String, String> params, Class<T> resultType) {
        return sendMsg(url, HTTPMETHOD.GET, null, null, params, resultType);
    }

    public static <T> T sendMsg(String url, HTTPMETHOD mothed, Map<String, String> header, Object content, Map<String, String> params, Class<T> resultType) {
        HttpClient client = HttpClients.createDefault();
        HttpRequestBase body = null;
        String result = "";
        String cont = content ==null?"":JSON.toJSONString(content);
        switch(mothed) {
            case POST:
                body = new HttpPost(url);
                if(StringUtils.isNotBlank(cont)) {
                    body.setHeader("Content-type", "application/json;charset=utf-8");
                    body.setHeader("Connetion", "close");
                    StringEntity entity = new StringEntity(cont, Charset.forName("UTF-8"));
                    entity.setContentType("application/json");
                    entity.setContentEncoding("UTF-8");
                    ((HttpPost)body).setEntity(entity);
                } else {
                    List<NameValuePair> nvps = new ArrayList<NameValuePair>();
                    for (String key : params.keySet()) {
                        String name = key;
                        String value = params.get(name);
                        nvps.add(new BasicNameValuePair(name, value));
                    }
                    try {
                        ((HttpPost)body).setEntity(new UrlEncodedFormEntity(nvps,"utf-8"));
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
                break;
            case GET:
                if(CollectionUtils.isNotEmpty(params)) {
                    url=url.lastIndexOf("?")==url.length()-1?url:url+"?";
                    StringBuilder sb  = new StringBuilder();
                    try {
                        for(String key : params.keySet()){
                            sb.append("&"+key+"="+URLEncoder.encode(params.get(key), "utf-8"));
                        }
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    url = url + sb.substring(1);
                }
                body = new HttpGet(url);
                body.setHeader("Connetion", "close");
                break;
            default:
                break;
        }
        try {
            if(CollectionUtils.isNotEmpty(header)) {
                for(String key : header.keySet()) {
                    body.addHeader(key, header.get(key));
                }
            }
            HttpResponse respone = client.execute(body);
            if(respone.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                log.error("[url:"+ url +",method:"+mothed.getMethod()+",param:"+ content+"]请求失败");
            } else {
                HttpEntity entity = respone.getEntity();
                result = EntityUtils.toString(entity);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(body != null) {
                body.releaseConnection();
            }
        }

        if(log.isDebugEnabled()) {
            log.debug(result);
        }
        T t = JSON.parseObject(result, resultType);
        return t;
    }

    public static String postMsg(String url, Object content) {
        return sendMsg(url, HTTPMETHOD.POST, content, null);
    }

    public static String getMsg(String url, Map<String, String> params) {
        return sendMsg(url, HTTPMETHOD.GET, null, params);
    }

    public static String sendMsg(String url, HTTPMETHOD mothed, Object content, Map<String, String> params) {
        HttpClient client = HttpClients.createDefault();
        HttpRequestBase body = null;
        String result = "";
        String cont = content ==null?"":JSON.toJSONString(content);
        switch(mothed) {
            case POST:
                body = new HttpPost(url);
                body.setHeader("Content-type", "application/json;charset=utf-8");
                body.setHeader("Connetion", "close");
                StringEntity entity = new StringEntity(cont, Charset.forName("UTF-8"));
                entity.setContentType("application/json");
                entity.setContentEncoding("UTF-8");
                ((HttpPost)body).setEntity(entity);
                break;
            case GET:
                if(CollectionUtils.isNotEmpty(params)) {
                    url=url.lastIndexOf("?")==url.length()-1?url:url+"?";
                    StringBuilder sb  = new StringBuilder();
                    try {
                        for(String key : params.keySet()){
                            sb.append("&"+key+"="+URLEncoder.encode(params.get(key), "utf-8"));
                        }
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    url = url + sb.substring(1);
                }
                body = new HttpGet(url);
                body.setHeader("Connetion", "close");
                break;
            default:
                break;
        }
        try {
            HttpResponse respone = client.execute(body);
            if(respone.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                log.info("[url:"+ url +",method:"+mothed.getMethod()+",param:"+ content+"]请求失败");
            } else {
                HttpEntity entity = respone.getEntity();
                result = EntityUtils.toString(entity);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(body != null) {
                body.releaseConnection();
            }
        }

        if(log.isDebugEnabled()) {
            log.debug(result);
        }
        return result;
    }

    /**
     * form data 提交方式
     *
     * @param url
     * @param param
     * @return
     */
    public static String doPostFile(String url, Map<String, String> fileInfo, Map<String, Object> param,  Map<String, String> header) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);

            if(header != null) {
                for(String key : header.keySet()) {
                    httpPost.setHeader(key, header.get(key));
                }
            }

            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
            for(String fi : fileInfo.keySet()) {
                File file = new File(fi);
                multipartEntityBuilder.addBinaryBody("file",file, ContentType.DEFAULT_BINARY, fileInfo.get(fi));
            }

//            ContentType contentType = ContentType.create(HTTP.PLAIN_TEXT_TYPE, HTTP.UTF_8);
            ContentType contentType = ContentType.create("text/plain", "UTF-8");
            // 创建参数列表
            if (param != null) {
                for (String key : param.keySet()) {
                    multipartEntityBuilder.addTextBody(key, param.get(key).toString(), contentType);
                }
            }

            HttpEntity httpEntity = multipartEntityBuilder.build();
            httpPost.setEntity(httpEntity);

            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }


    public static void main(String[] args) throws Exception {
        JSONObject object = new JSONObject();
        object.put("type", "Face_Features");
        object.put("content", "http://192.168.0.78:50006/faceImg/45/eUea2iyH.jpg");
         String  result = post("http://192.168.0.161:7771/basic/adc111/sync/task", object.toString());
        System.out.println(result);
    }
}
